package cn.jbolt.ai.app.service.impl;


import cn.jbolt.ai.core.chain.config.AppConfigConstant;
import cn.jbolt.ai.app.entity.AiAppConfig;
import cn.jbolt.ai.app.entity.AiAppNode;
import cn.jbolt.ai.app.service.AiAppConfigService;
import cn.jbolt.ai.app.service.AiAppNodeService;
import cn.jbolt.ai.app.service.AiAppService;
import cn.jbolt.ai.core.chain.ChainCenter;
import cn.jbolt.ai.core.chain.node.InnerNodeType;
import cn.jbolt.ai.core.chain.node.NodeProviderCenter;
import cn.jbolt.ai.core.chain.node.start.StartNode;
import cn.jbolt.util.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.jbolt.ai.app.dao.AiAppDesignMapper;
import cn.jbolt.ai.app.entity.AiAppDesign;
import cn.jbolt.ai.app.service.AiAppDesignService;
import cn.jbolt.util.Result;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class AiAppDesignServiceImpl extends ServiceImpl<AiAppDesignMapper, AiAppDesign> implements AiAppDesignService {

    @Autowired
    private AiAppService appService;
    @Autowired
    private AiAppNodeService nodeService;
    @Autowired
    private AiAppConfigService configService;

    @Override
    public Result<AiAppDesign> getDesignById(Long id) {
        QueryWrapper<AiAppDesign> wrapper = new QueryWrapper<>();
        wrapper.eq("app_id", id);
        AiAppDesign design = this.getOne(wrapper);
        if (design != null) {
            return Result.success(design);
        } else {
            return Result.error("AI应用设计不存在");
        }
    }


    @Override
    public Result add(AiAppDesign design) {
        boolean save = this.save(design);
        if (save) {
            return Result.success();
        } else {
            return Result.error("添加失败");
        }
    }

    @Override
    public Result update(AiAppDesign design) {
        Long appId = design.getAppId();
        String fieldsName = design.getFieldsName();
        String fieldsValue = design.getFieldsValue();
        Result<AiAppDesign> result = getDesignById(appId);
        if (result.isError()) {
            return result;
        }
        UpdateWrapper updateWrapper = new UpdateWrapper();
        updateWrapper.eq("app_id", appId);
        updateWrapper.set(fieldsName, fieldsValue);
        if (this.update(updateWrapper)) {
            return Result.success();
        } else {
            return Result.error("更新失败");
        }
    }

    @Override
    public Result del(Long id) {
        Result<AiAppDesign> result = getDesignById(id);
        if (result.isError()) {
            return result;
        }
        if (removeById(id)) {
            return Result.success();
        } else {
            return Result.error("删除失败");
        }
    }

    @Override
    public Result testRun(Long id) {
        Result<AiAppDesign> result = getDesignById(id);
        if (result.isError()) {
            return result;
        }
        AiAppDesign design = result.getData();
        Result<List<AiAppNode>> convertResult = convertDesignToAppNodes(design);
        if (convertResult.isError()) {
            return convertResult;
        }
        ChainCenter.registerDevAppChain(design.getAppId(), convertResult.getData());
        return Result.success();
    }

    /**
     * 将编排转换为应用节点
     *
     * @param design
     * @return
     */
    private Result<List<AiAppNode>> convertDesignToAppNodes(AiAppDesign design) {
        ArrayNode nodes = JSONUtil.toJsonArray(design.getNodes());
        ArrayNode edges = JSONUtil.toJsonArray(design.getEdges());
        HashMap<Long, AiAppNode> nodeMap = new HashMap<>();
        HashMap<Long, ObjectNode> afterMap = new HashMap<>();
        for (JsonNode node : nodes) {
            nodeMap.put(node.get("id").asLong(), convertJsonToAppNode(node, design));
        }
        for (JsonNode edge : edges) {
            Long source = edge.get("source").asLong();
            Long target = edge.get("target").asLong();
            String branch = edge.get("sourceHandle").asText();
            ObjectNode after = afterMap.get(source); //{"success":["id1","id2"]}
            if (after == null) {
                after = JSONUtil.createObjectNode();
                afterMap.put(source, after);
            }
            ArrayNode branchNodes = (ArrayNode) after.get(branch);
            if (branchNodes == null) {
                branchNodes = JSONUtil.createArrayNode();
                after.put(branch, branchNodes);
            }
            branchNodes.add(target);
        }
        return filterNodes(nodeMap, afterMap);
    }

    /**
     * 过滤出有效节点，条件就是被检测节点必须是从start类型的节点发起的
     *
     * @param nodeMap
     * @param afterMap
     * @return
     */
    private Result<List<AiAppNode>> filterNodes(HashMap<Long, AiAppNode> nodeMap, HashMap<Long, ObjectNode> afterMap) {
        HashSet<Long> nodeIds = new HashSet<>();
        List<AiAppNode> nodes = new ArrayList<>();
        Iterator<AiAppNode> iterator = nodeMap.values().iterator();
        try {

            while (iterator.hasNext()) {
                AiAppNode node = iterator.next();
                if (node.getType().equals(InnerNodeType.APP_CONFIG)) {
                    //配置节点，不解析
                    continue;
                }
                Object nodeProvider = NodeProviderCenter.getNodeProvider(node.getType());
                if (nodeProvider instanceof StartNode) {
                    //节点类型实现了StartNode接口的节点，则认为是起始节点，从该起始节点向后找
                    if (nodeIds.add(node.getId())) {
                        nodes.add(node);
                        node.setAfters(JSONUtil.toJson(afterMap.get(node.getId())));
                        addAfterNodes(node, nodeMap, afterMap, nodeIds, nodes);
                    }
                }
            }
        } catch (Exception e) {
            return Result.error(e.getMessage());
        }


        return Result.success(nodes);
    }

    /**
     * 递归查找后置节点
     *
     * @param currentNode
     * @param nodeMap
     * @param afterMap
     * @param ids
     * @param nodes
     * @return
     */
    private void addAfterNodes(AiAppNode currentNode, HashMap<Long, AiAppNode> nodeMap, HashMap<Long, ObjectNode> afterMap, HashSet<Long> ids, List<AiAppNode> nodes) {
        ObjectNode afters = afterMap.get(currentNode.getId());
        if (afters == null) {
            return;
        }
        //{"success":["id1","id2"]}
        afters.elements().forEachRemaining(branch -> {
            branch.elements().forEachRemaining(afterId -> {
                long id = afterId.asLong();
                if (ids.add(id)) {
                    AiAppNode node = nodeMap.get(id);
                    nodes.add(node);
                    node.setAfters(JSONUtil.toJson(afterMap.get(node.getId())));
                    addAfterNodes(node, nodeMap, afterMap, ids, nodes);
                }
            });
        });
    }

    private AiAppNode convertJsonToAppNode(JsonNode json, AiAppDesign design) {
        AiAppNode node = new AiAppNode();
        node.setId(json.get("id").asLong());
        node.setType(json.get("type").asText());
        node.setAppId(design.getAppId());
        node.setConfig(json.get("data"));
        return node;
    }

    @Override
    @Transactional
    public Result publish(Long id) {

        Result result = appService.getOnlyAppById(id);
        if (result.isError()) {
            return result;
        }
        Result<AiAppDesign> designResult = getDesignById(id);
        if (designResult.isError()) {
            return designResult;
        }
        //先查询之前是否有node跟配置
        Result delNodeResult = nodeService.deleteNodesByAppId(id);
        if (delNodeResult.isError()) {
            return delNodeResult;
        }
        Result delConfigResult = configService.deleteByAppId(id);
        if (delConfigResult.isError()) {
            return delConfigResult;
        }

        try {
            AiAppDesign appDesign = designResult.getData();
            AiAppDesign design = appDesign;
            Result<List<AiAppNode>> nodes = convertDesignToAppNodes(design);
            List<AiAppNode> nodesList = nodes.getData();
            List<AiAppConfig> nodeConfigList = new ArrayList<>();
            for (AiAppNode node : nodesList) {
                AiAppConfig nodeConfig = new AiAppConfig();
                nodeConfig.setLinkId(node.getId());
                nodeConfig.setLinkType(AppConfigConstant.LINK_TYPE_NODE);
                nodeConfig.setConfigValue(JSONUtil.toJson(node.getConfig()));
                nodeConfigList.add(nodeConfig);
            }
            //把nodesList 跟nodeConfigList 添加到数据
            Result addedNodeResult = nodeService.addNodes(nodesList);
            if(addedNodeResult.isError()){
                return addedNodeResult;
            }
            //从design中取出uiConfig存到相应的节点上
            ArrayNode designObjectNode = JSONUtil.toJsonArray(appDesign.getNodes());
            for (JsonNode node : designObjectNode) {
                if (node.get("type").asText().equals(AppConfigConstant.CONFIG_NODE_APP)) {
                    AiAppConfig appConfig = new AiAppConfig();
                    appConfig.setLinkId(id);
                    appConfig.setLinkType(AppConfigConstant.LINK_TYPE_APP);
                    appConfig.setConfigValue(JSONUtil.toJson(node.get("data")));
                    nodeConfigList.add(appConfig);
                }
            }


            Result addConfigResult = configService.addConfigs(nodeConfigList);
            if(addConfigResult.isError()){
                return addConfigResult;
            }
            ChainCenter.remove(id);
            return Result.success("发布成功");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(e.getMessage());
        }
    }
}
